package imgshare.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.extra.ftp.Ftp;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import imgshare.common.api.CommonResult;
import imgshare.mapper.ImageMapper;
import imgshare.model.Image;
import imgshare.model.vo.ImageCondition;
import imgshare.model.vo.UserInfo;
import imgshare.service.ImageService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.time.LocalDateTime;
import java.util.List;

import static com.google.common.base.Verify.verifyNotNull;

@RestController
@RequestMapping("/images")
public class ImageController {

    @Value("${front.url}")
    private String FRONT_URL;

    @Value("${ftp.host}")
    private String FTP_HOST;

    @Value("${ftp.port}")
    private Integer FTP_PORT;

    @Value("${ftp.user}")
    private String FTP_USER;

    @Value("${ftp.password}")
    private String FTP_PASSWORD;

    @Autowired
    private ImageService imageService;
    @Autowired
    private ImageMapper imageMapper;
    private static final Log log = LogFactory.get();

    /**
     * 根据条件查找图片集，条件关系and
     * @param pageNum
     * @param pageSize
     * @param category
     * @param userId 图片集创建者id
     * @param title
     * @return
     */
    @GetMapping
    public CommonResult<?> listAllFilterByCondition(@RequestParam(required = false, defaultValue = "1") Integer pageNum,
                                                    @RequestParam(required = false, defaultValue = "9") Integer pageSize,
                                                    @RequestParam(required = false) String category,
                                                    @RequestParam(required = false) Integer userId,
                                                    @RequestParam(required = false) String title) {

        ImageCondition imageCondition = new ImageCondition();
        imageCondition.setCategory(category);
        imageCondition.setTitle(title);
        imageCondition.setUserId(userId);
        imageCondition.setOpen(true);
        imageCondition.setLocked(false);

        PageInfo<Image> page = PageHelper.startPage(pageNum, pageSize)
                .doSelectPageInfo(() -> imageService.findWithSimpleUserInfoByCondition(imageCondition));
        return CommonResult.success(page);
    }

    @GetMapping("/{id}")
    public CommonResult<Image> find(@PathVariable int id) {
        Image foundedImage = imageService.getImageById(id);

        verifyNotNull(foundedImage, "参数错误");

        return CommonResult.success(foundedImage);
    }

    @RequiresAuthentication
    @PostMapping("/update")
    public CommonResult<?> update(@RequestBody @Validated Image image) {

        image.setUpdatedTime(LocalDateTime.now());

        imageService.update(image);
        log.info("图片(id:{})更新成功", image.getId());

        return CommonResult.success();

    }

    /**
     * 我收藏的图片集
     * @param pageNum
     * @param pageSize
     * @param userId
     * @return
     */
    @RequiresAuthentication
    @GetMapping("/collect")
    public CommonResult<?> listCollectedImages(@RequestParam(required = false, defaultValue = "1") Integer pageNum,
                                               @RequestParam(required = false, defaultValue = "9") Integer pageSize,
                                               @RequestParam Integer userId) {

        PageInfo<Image> collectedImages = PageHelper.startPage(pageNum, pageSize).doSelectPageInfo(
                () -> imageService.findCollectedImages(userId));
        return CommonResult.success(collectedImages);
    }

    /**
     * 我关注的用户所发布的图片集
     * @param pageNum
     * @param pageSize
     * @param userId
     * @return
     */
    @RequiresAuthentication
    @GetMapping("/post_by_my_following_users")
    public CommonResult<?> listMyFollowingUsersPostImages(@RequestParam(required = false, defaultValue = "1") Integer pageNum,
                                                                    @RequestParam(required = false, defaultValue = "9") Integer pageSize,
                                                                    @RequestParam Integer userId) {

        PageInfo<Image> pageInfo = PageHelper.startPage(pageNum, pageSize).doSelectPageInfo(
                () -> imageService.findMyFollowingUsersPostedImages(userId)
        );
        return CommonResult.success(pageInfo);
    }

    /**
     * 图片集上传，持久到数据库，同时图片上传到ftp服务器，路径为“ftp默认目录/imgshare/{imageId}”
     * @param files
     * @param image
     * @return
     */
    @RequiresAuthentication
    @PostMapping("/uploads")
    public synchronized CommonResult<?> upload(@RequestPart("file") MultipartFile[] files, @Validated Image image) {

        log.info("image: {}", image.toString());
        log.info(String.valueOf(files.length));

        if (files.length == 0) {
            return CommonResult.failed("图片不能为空");
        }

        MultipartFile file = files[0];
        String randomUUID = IdUtil.simpleUUID();
        String originalFilename = file.getOriginalFilename();
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
        String imageName = randomUUID + suffix;

        LocalDateTime now = LocalDateTime.now();
        image.setCreatedTime(now);
        image.setUpdatedTime(now);
        image.setUserId(((UserInfo) SecurityUtils.getSubject().getPrincipal()).getId());

        ImageCondition imageCondition = new ImageCondition();
        imageCondition.setTitle(image.getTitle());
        imageCondition.setUserId(image.getUserId());
        List<Image> foundedImageList = imageService.findByCondition(imageCondition);
        if (foundedImageList != null && !foundedImageList.isEmpty()) {
            log.info("存在同一用户创建的同一主题图片集[{}]，更新imageUrl", image.getTitle());

            Image newImage = new Image();
            Image originalImage = foundedImageList.get(0);
            BeanUtil.copyProperties(originalImage, newImage);
            image.setImageUrl(FRONT_URL + originalImage.getId() + "/" + imageName);
            newImage.setImageUrl(image.getImageUrl() + "," + newImage.getImageUrl());
            System.out.println("更新用的imageUrl：" + newImage.getImageUrl());

            // 先往服务器上传图片，成功后再更新数据库
            // 上传图片到服务器，目录为：/ftp默认目录/imgshare/图片集id/图片名
            try {
                uploadToFtp("./imgshare/" + originalImage.getId(),imageName,file.getInputStream());
            } catch (IOException e) {
                log.error(e,"上传图片异常");
                return CommonResult.failed("上传图片出错");
            }
            imageService.update(newImage);
        } else { // 不存在同一用户创建的同一主题图片集
            image.setImageUrl("temp");
            imageService.add(image);
            int id = image.getId();
            String imageUrl = FRONT_URL + id + "/" + imageName;
            image.setImageUrl(imageUrl);
            imageService.update(image);
            // 上传图片到服务器，目录为：/ftp默认目录/imgshare/图片集id/图片名
            try {
                uploadToFtp("./imgshare/" + id, imageName, file.getInputStream());
            } catch (IOException e) {
                log.error(e,"上传图片异常");
                return CommonResult.failed("上传图片出错");
            }
            log.info("不存在同一用户创建的同一主题图片集[{}]，添加数据", image.getTitle());

        }
        return CommonResult.success();
    }

    /**
     * 文件下载，下载路径为“ftp服务器默认目录/imgshare/{imageId}”，ftp服务器不在同一台机器时，
     * 将目录内容下载到临时目录，再进行zip处理，已流形式写出
     * @param imageId
     * @param response
     */
    @GetMapping(value = "/download/{imageId}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    public void download(@PathVariable Integer imageId, HttpServletResponse response) {
        response.setHeader("content-type", MediaType.APPLICATION_OCTET_STREAM_VALUE);
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        Image foundedImage = imageService.getImageById(imageId);
        if (foundedImage == null) {
            log.info("要下载的图片不存在");
            return;
        }
        // 下载文件目录保存到临时目录，zip压缩后返回（图片集保存目录路径为imgshare/{imageId})
        Ftp ftp = new Ftp(FTP_HOST, FTP_PORT, FTP_USER, FTP_PASSWORD);
        ftp.getClient().enterLocalPassiveMode();
        try {
            File tmpFile = Files.createTempDirectory("imgshare").toFile();
            tmpFile.deleteOnExit();
            response.setHeader("Content-Disposition", "attachment;filename=" + tmpFile.getName());
            ftp.recursiveDownloadFolder("./imgshare/" + imageId, tmpFile);
            ftp.close();
            ServletOutputStream outputStream = response.getOutputStream();
            ZipUtil.zip(outputStream, StandardCharsets.UTF_8,true,(file)->{return true;},tmpFile);
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            log.error(e);
        }
    }

    private void uploadToFtp(String dir,String fileName,InputStream inputStream) throws IOException {
        Ftp ftp = new Ftp(FTP_HOST, FTP_PORT, FTP_USER, FTP_PASSWORD);
        ftp.getClient().enterLocalPassiveMode();
        ftp.upload(dir, fileName, inputStream);
        ftp.close();
    }
}